Skip to content

Save fiber stacks on Fiber directly instead of using Hash#27

Merged
ysbaddaden merged 2 commits intomainfrom
refactor/put-fiber-trace-on-fiber-objects
Mar 9, 2026
Merged

Save fiber stacks on Fiber directly instead of using Hash#27
ysbaddaden merged 2 commits intomainfrom
refactor/put-fiber-trace-on-fiber-objects

Conversation

@ysbaddaden
Copy link
Contributor

@ysbaddaden ysbaddaden commented Mar 28, 2025

I noticed a few things:

  1. we can save the fiber stacks directly on Fiber instead of storing each into a different global Hash;
  2. we can safely iterate fibers using Fiber.each (thread safe linked list);
  3. bonus: we don't need to monkey patch Fiber.inactive anymore;
  4. bonus: we don't need track_fiber to be a macro anymore (renamed caller_stack);
  5. bonus: we can list the main fiber of threads, their spawn stack is empty (it could be the stack that led to start the thread) but their yield stack can be interesting.

The above allows us to not need an explicit lock anymore: we're always setting the stack for the current fiber, and we can have a few checks to make sure we can use said stack from another thread.

Which leads me to the last point: we can generate a backtrace from a Slice(Void*) directly (with a few changes) and we can store stacks as Slice(Void*) directly instead of Array(Void*).

The stacks slice is a struct and if its size won't change, then only the pointer will, so we wouldn't need thread synchronization... except for one caveat: the size can change from 0 to N (see comments) so we check for null pointer and size == 0 (to be resilient to any parallel write reorder), before deciding to use the stack.

I'm having some second thoughts about that. Maybe an Array would be safer: we'd merely update a pointer in place 🤔

I still save the stack as Array(Void*) then expose views into the array as Slice(Void*). The underlying buffer size is either 0 or DEPTH + SKIP.

@ysbaddaden ysbaddaden added the enhancement New feature or request label Mar 28, 2025
@ysbaddaden ysbaddaden self-assigned this Mar 28, 2025
@ysbaddaden ysbaddaden marked this pull request as draft March 28, 2025 12:00
@ysbaddaden

This comment was marked as outdated.

@ysbaddaden ysbaddaden marked this pull request as ready for review March 28, 2025 12:47
straight-shoota pushed a commit to crystal-lang/crystal that referenced this pull request Apr 17, 2025
…15615)

Internal refactor: allows to generate a decoded backtrace for any given instruction pointer, without requiring an `Array` or an `Exception::CallStack` object.

My use case is crystal-lang/perf-tools#27 where I use slices and where I could merely call this helper method.
Also allows to generate backtraces for Slice(Void*) directly (no need
for an Array anymore).
@ysbaddaden ysbaddaden force-pushed the refactor/put-fiber-trace-on-fiber-objects branch from b40fcbd to 8390228 Compare March 5, 2026 11:42
@ysbaddaden
Copy link
Contributor Author

ysbaddaden commented Mar 5, 2026

Rebased from master, squashed some commits, and tested again. I believe this is ready to merge, so I can rework #26 to have a view into the "current state" of all fibers in the program, not only where each fiber is running, but what are pending fibers waiting on ❤️

@straight-shoota straight-shoota moved this from Review to Approved in Multi-threading Mar 6, 2026
@ysbaddaden ysbaddaden merged commit 8dea7df into main Mar 9, 2026
@ysbaddaden ysbaddaden deleted the refactor/put-fiber-trace-on-fiber-objects branch March 9, 2026 11:15
@github-project-automation github-project-automation bot moved this from Approved to Done in Multi-threading Mar 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants